package cn.stimd.spring.context.support;

import cn.stimd.spring.beans.BeansException;
import cn.stimd.spring.beans.factory.BeanFactory;
import cn.stimd.spring.beans.factory.config.AutowireCapableBeanFactory;
import cn.stimd.spring.beans.factory.config.BeanFactoryPostProcessor;
import cn.stimd.spring.beans.factory.config.ConfigurableBeanFactory;
import cn.stimd.spring.beans.factory.support.BeanDefinitionRegistry;
import cn.stimd.spring.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import cn.stimd.spring.context.ApplicationContext;
import cn.stimd.spring.context.ConfigurableApplicationContext;
import cn.stimd.spring.context.LifecycleProcessor;
import cn.stimd.spring.context.event.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.ResolvableType;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringValueResolver;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Created by Stimd
 * 项目地址：https://gitee.com/stimd/spring-wheel
 * 公众号：Java编程探微
 */
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
    public static final String ENVIRONMENT_BEAN_NAME = "environment";
    protected Log logger = LogFactory.getLog(getClass());

    private String id = ObjectUtils.identityToString(this);
    private String displayName = ObjectUtils.identityToString(this);
    private ConfigurableEnvironment environment = new StandardEnvironment();
    private ApplicationContext parent;
    private final Object startupShutdownMonitor = new Object();     //容器启动&关闭的监视锁
    private Thread shutdownHook;                                    //虚拟机的关闭回调
    private final AtomicBoolean active = new AtomicBoolean();       //启用标识
    private final AtomicBoolean closed = new AtomicBoolean();       //关闭标识
    private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();
    private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(this);
    private LifecycleProcessor lifecycleProcessor;
    //事件多播器
    private ApplicationEventMulticaster applicationEventMulticaster;
    //临时存储的监听器类列表
    private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();

    @Override
    public void refresh() {
        synchronized (this.startupShutdownMonitor) {
            //1. 准备工作，比如加载PropertySource
            prepareRefresh();

            //2. 通知子类刷新BeanFactory
            ConfigurableBeanFactory beanFactory = obtainFreshBeanFactory();

            //3. ApplicationContext使用BeanFactory前的准备工作，比如添加必要的组件
            prepareBeanFactory(beanFactory);

            try {
                //4. 扩展点，允许子类进行自定义操作（主要是与BeanFactory有关的）
                postProcessBeanFactory(beanFactory);

                //5. 执行BeanFactoryPostProcessor的相关逻辑
                invokeBeanFactoryPostProcessors(beanFactory);

                //6. 注册BeanPostProcessor
                registerBeanPostProcessors(beanFactory);

                //7. 注册事件多播器，默认为SimpleApplicationEventMulticaster
                initApplicationEventMulticaster(beanFactory);

                //8. 扩展点，允许子类进行自定义操作（与BeanFactory无关）
                onRefresh();

                //9. 注册监听器，发送早期事件（earlyApplicationEvents）
                registerListeners();

                //10. 创建容器中剩余的单例Bean
                finishBeanFactoryInitialization(beanFactory);

                //11. 发送refresh完成事件
                finishRefresh();
            }catch (Exception e){
                //销毁已创建的单例Bean，释放资源
                destroyBeans();
                this.active.set(false);
                throw e;
            }
        }
    }


    //step-1 刷新前的准备，将Context设置为活跃的
    private void prepareRefresh() {
        this.closed.set(false);
        this.active.set(true);

        //初始化PropertySources（略）
    }


    //step-2 通知子类刷新BeanFactory，refreshBeanFactory方法是供子类扩展的，典型应用是ClassPathXmlApplicationContext
    //通过XmlBeanDefinitionReader加载Spring的xml配置文件
    private ConfigurableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        return getBeanFactory();
    }


    //step-3 BeanFactory要变得可用，还需要设置一些组件
    private void prepareBeanFactory(ConfigurableBeanFactory beanFactory) {
        //1) 设置BeanFactory的相关组件，ClassLoader、BeanExpressionResolver、PropertyEditorRegistrar（OMIT）
        //2) 注册BeanPostProcessor
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));   //用于处理Aware感知接口

        //3) 注册依赖项组件（调用BeanFactoryPostProcessor和BeanPostProcessor可能会用到这些Bean，因此需要先加载）
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);

        //4) 注册单例
        beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    }


    //step-4 扩展点，允许子类进行自定义的操作，比如添加BeanPostProcessor等
    protected void postProcessBeanFactory(ConfigurableBeanFactory beanFactory) { }


    //step-5 调用已注册的BeanFactoryPostProcessor，典型应用是执行ConfigurationClassPostProcessor处理配置类
    protected void invokeBeanFactoryPostProcessors(ConfigurableBeanFactory beanFactory) {
        List<BeanDefinitionRegistryPostProcessor> processors = new ArrayList<>();
        List<String> names = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class);
        for (String name : names) {
            processors.add(beanFactory.getBean(name, BeanDefinitionRegistryPostProcessor.class));
        }

        if (beanFactory instanceof BeanDefinitionRegistry) {
            BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
            for (BeanDefinitionRegistryPostProcessor processor : processors) {
                //执行BeanDefinition注册相关操作
                processor.postProcessBeanDefinitionRegistry(registry);
                processor.postProcessBeanFactory(beanFactory);
            }
        }
    }


    //step-6 此时在step-3、step4或其他时刻定义的BeanPostProcessor仍是BeanDefinition形态，接下来就要处理Bean了，
    //因此需要通过getBean方法获取BeanPostProcessor的实例，并添加到BeanFactory的BeanPostProcessor集合中
    protected void registerBeanPostProcessors(ConfigurableBeanFactory beanFactory) {
        PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory);
        logger.info("[Context] [容器刷新] --> 注册BeanProcessor完毕，共计" + beanFactory.getBeanPostProcessorCount());
    }


    //step-7 注册事件多播器
    protected void initApplicationEventMulticaster(ConfigurableBeanFactory beanFactory) {
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster();
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        logger.info("[Context] [容器刷新] --> 注册ApplicationEventMulticaster完毕");
    }


    //step-8 扩展点，允许子类完成某些操作，典型应用是EmbeddedWebApplicationContext完成了创建内嵌Servlet容器的逻辑
    //需要注意，这些操作已经与BeanFactory无关，因此没有提供参数，这是与step4的扩展逻辑的主要区别
    protected void onRefresh() {
        //NO-OP
    }


    //step-9 注册事件监听器
    protected void registerListeners() {
        //注册手动添加的监听器
        for (ApplicationListener<?> listener : this.applicationListeners) {
            this.applicationEventMulticaster.addApplicationListener(listener);
        }

        //注册BeanFactory中的事件监听器
        List<String> names = getBeanNamesForType(ApplicationListener.class);
        for (String name : names) {
            this.applicationEventMulticaster.addApplicationListener((ApplicationListener<?>) getBean(name));
        }
        logger.info("[Context] [容器刷新] --> 注册ApplicationListener完毕，共计" + names.size());

        //发布早期事件（略）
    }


    //step-10 BeanFactory的最后操作，实例化所有的单例Bean
    protected void finishBeanFactoryInitialization(ConfigurableBeanFactory beanFactory) {
        //注册字符串解析器，用于解析@Value注解
        if (!beanFactory.hasEmbeddedValueResolver()) {
            beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
                @Override
                public String resolveStringValue(String strVal) {
                    return getEnvironment().resolvePlaceholders(strVal);
                }
            });
        }

        //实例化所有的单例Bean
        beanFactory.preInstantiateSingletons();
        logger.info("[Context] [容器刷新] --> 初始化所有的单例Bean完毕");
    }


    //step-11 收尾工作
    protected void finishRefresh() {
        //初始化LifecycleProcessor并启动生命周期组件
        this.lifecycleProcessor = new DefaultLifecycleProcessor(getBeanFactory());
        this.lifecycleProcessor.onRefresh();

        //发送ContextRefreshedEvent事件
        logger.info("[Context] [容器刷新] --> 刷新完毕，发送ContextRefreshedEvent事件");
        publishEvent(new ContextRefreshedEvent(this));

        //注册JMX（略）
    }


    //---------------------------------------------------------------------
    // 重写&实现
    //---------------------------------------------------------------------

    // ------------------------------- BeanFactory接口
    @Override
    public Object getBean(String name) throws RuntimeException {
        return getBeanFactory().getBean(name);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) {
        return getBeanFactory().getBean(name, requiredType);
    }

    @Override
    public <T> T getBean(Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(requiredType);
    }

    @Override
    public Class<?> getType(String name) {
        return getBeanFactory().getType(name);
    }

    @Override
    public boolean isTypeMatch(String name, ResolvableType typeToMatch) throws BeansException {
        return getBeanFactory().isTypeMatch(name, typeToMatch);
    }

    @Override
    public boolean isTypeMatch(String name, Class<?> typeToMatch) throws BeansException {
        return getBeanFactory().isTypeMatch(name, typeToMatch);
    }

    @Override
    public List<String> getBeanNamesForType(Class<?> type) {
        return getBeanFactory().getBeanNamesForType(type);
    }

    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
        return getBeanFactory().getBeansOfType(type);
    }

    @Override
    public boolean containsBeanDefinition(String beanName) {
        return getBeanFactory().containsBeanDefinition(beanName);
    }


    // ------------------------------- ResourcePatternResolver接口
    @Override
    public Resource[] getResources(String locationPattern) throws IOException {
        return this.resourcePatternResolver.getResources(locationPattern);
    }


    // ------------------------------- ApplicationContext接口
    @Override
    public String getId() {
        return id;
    }

    @Override
    public String getDisplayName() {
        return displayName;
    }

    @Override
    public AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException {
        return getBeanFactory();
    }


    // ------------------------------- ConfigurableApplicationContext接口
    @Override
    public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
        this.beanFactoryPostProcessors.add(postProcessor);
    }

    @Override
    public void addApplicationListener(ApplicationListener<?> listener) {
        if (this.applicationEventMulticaster != null) {
            this.applicationEventMulticaster.addApplicationListener(listener);
        }

        this.applicationListeners.add(listener);
    }

    @Override
    public ConfigurableEnvironment getEnvironment() {
        return environment;
    }

    @Override
    public void setEnvironment(ConfigurableEnvironment environment) {
        this.environment = environment;
    }

    @Override
    public void close() {
        synchronized (this.startupShutdownMonitor) {
            //执行实际关闭逻辑
            doClose();

            //移除已注册的虚拟机钩子，close方法已经显式地关闭了上下文
            if (this.shutdownHook != null) {
                try {
                    Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
                }
                catch (IllegalStateException ex) {
                    // ignore - VM is already shutting down
                }
            }
        }
    }

    protected void destroyBeans() {
        getBeanFactory().destroySingletons();
    }
    protected void closeBeanFactory() { }
    protected void onClose() { }

    @Override
    public void registerShutdownHook() {
        if (this.shutdownHook == null) {
            this.shutdownHook = new Thread() {
                @Override
                public void run() {
                    synchronized (startupShutdownMonitor) {
                        doClose();
                    }
                }
            };
            Runtime.getRuntime().addShutdownHook(this.shutdownHook);
        }
    }

    protected void doClose() {
        if (this.active.get() && this.closed.compareAndSet(false, true)) {
            logger.info("[Context] [容器关闭] --> 发送ContextClosedEvent事件");

            //发送上下文关闭事件
            try {
                publishEvent(new ContextClosedEvent(this));
            } catch (Throwable ex) {
                logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
            }

            //销毁JMX（略）
            //处理LifecycleProcessor
            if (this.lifecycleProcessor != null) {
                try {
                    this.lifecycleProcessor.onClose();
                } catch (Throwable ex) {
                    logger.warn("[Context] [容器关闭] --> 关闭LifecycleProcessor失败", ex);
                }
            }

            //销毁所有的单例Bean
            destroyBeans();

            //关闭BeanFactory
            closeBeanFactory();

            //留给子类扩展，比如EmbeddedWebApplicationContext关闭了嵌入式Servlet容器
            onClose();

            this.active.set(false);
        }
    }

    @Override
    public void setParent(ApplicationContext parent) {
        this.parent = parent;
        if (parent != null) {
            Environment parentEnvironment = parent.getEnvironment();
            if (parentEnvironment instanceof ConfigurableEnvironment) {
                getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
            }
        }
    }

    public ApplicationContext getParent() {
        return this.parent;
    }

    // ------------------------------- ApplicationEventPublisher接口
    @Override
    public void publishEvent(ApplicationEvent event) {
        this.applicationEventMulticaster.multicastEvent(event);
    }

    //---------------------------------------------------------------------
    // Getter&Setter
    //---------------------------------------------------------------------

    //---------------------------------------------------------------------
    // 模板方法
    //---------------------------------------------------------------------

    protected abstract void refreshBeanFactory();
}
